import * as THREE from 'three';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'

export class SplineEditor {
  constructor(options) {
    // 从options中解构所需参数
    const {
      container,
      scene,
      camera,
      renderer,
      controls,
      initialPositions = [],
    } = options;

    // 保存传入的依赖
    this.container = container;
    this.scene = scene;
    this.camera = camera;
    this.renderer = renderer;
    this.controls = controls;

    // 初始化内部状态
    this.pointer = new THREE.Vector2();
    this.onUpPosition = new THREE.Vector2();
    this.onDownPosition = new THREE.Vector2();
    this.raycaster = new THREE.Raycaster();
    this.splineHelperObjects = [];
    this.splines = {};
    this.positions = [];
    this.point = new THREE.Vector3();
    this.ARC_SEGMENTS = 200;

    // 控制参数
    this.params = {
      uniform: true,
      tension: 0.5,
      centripetal: true,
      chordal: true
    };

    // 初始化几何体（复用同一个几何体）
    // 1. 创建纹理
    const textureLoader = new THREE.TextureLoader();
    const spriteTexture = textureLoader.load('/image/zhandian.png');

    // 2. 创建材质
    const spriteMaterial = new THREE.SpriteMaterial({
      map: spriteTexture,
      transparent: true, // 启用透明度
    });

    this.pointGeometry = spriteMaterial;

    // 初始化曲线
    this.initSplines(initialPositions);
    this.initTransformControls();
    this.initEventListeners();
  }

  initSplines(initialPositions) {
    // 初始化控制点
    for (let i = 0; i < Math.max(4, initialPositions.length); i++) {
      this.addSplineObject(initialPositions[i],i);
    }

    // 创建曲线几何体
    const curveGeometry = new THREE.BufferGeometry();
    curveGeometry.setAttribute(
      'position',
      new THREE.BufferAttribute(new Float32Array(this.ARC_SEGMENTS * 3), 3)
    );

    // 创建三种曲线类型
    const curveTypes = [
      { type: 'catmullrom', color: 0xff0000, key: 'uniform' },
      { type: 'centripetal', color: 0x00ff00, key: 'centripetal' },
      { type: 'chordal', color: 0x0000ff, key: 'chordal' }
    ];

    curveTypes.forEach(({ type, color, key }) => {
      const curve = new THREE.CatmullRomCurve3(this.positions);

      curve.curveType = type;
      curve.tension = 0.2;
      curve.mesh = new THREE.Line(
        curveGeometry.clone(),
        new THREE.LineBasicMaterial({ color, })
      );
      curve.mesh.castShadow = true;
      this.splines[key] = curve;
      this.scene.add(curve.mesh);
    });

    this.updateSplineOutline();
  }

  initTransformControls() {
    this.transformControl = new TransformControls(
      this.camera,
      this.renderer.domElement
    );
    this.transformControl.addEventListener('change', () => this.render());

    this.transformControl.addEventListener('objectChange', () => {
      this.updateSplineOutline();
    });
    this.transformControl.addEventListener('dragging-changed', (event) => {
      this.controls.enabled = !event.value;
    });
    // 只允许平移（XZ）和旋转
    this.transformControl.setMode('translate');
    this.transformControl.setSpace('world'); // 使用世界坐标系

    // 禁用 Y 轴平移
    this.transformControl.showY = false;
    this.scene.add(this.transformControl.getHelper());
  }

  initEventListeners() {
    this.onPointerDown = this.onPointerDown.bind(this);
    this.onPointerUp = this.onPointerUp.bind(this);
    this.onPointerMove = this.onPointerMove.bind(this);

    this.container.addEventListener('pointerdown', this.onPointerDown);
    this.container.addEventListener('pointerup', this.onPointerUp);
    this.container.addEventListener('pointermove', this.onPointerMove);
  }

  onPointerDown(event) {
    const rect = this.container.getBoundingClientRect();
    this.onDownPosition.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    this.onDownPosition.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  }

  onPointerUp(event) {
    const rect = this.container.getBoundingClientRect();
    this.onUpPosition.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    this.onUpPosition.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

    if (this.onDownPosition.distanceTo(this.onUpPosition) === 0) {
      this.transformControl.detach();
      this.render();
    }
  }
  getPositions() {
    const strplace = [];
    for (let i = 0; i < this.splineHelperObjects.length; i++) {
      const p = this.splineHelperObjects[i].position;
      strplace.push(new THREE.Vector3(p.x, p.y, p.z));
    }
    return [strplace, this.splines['uniform']];
  }
  onPointerMove(event) {
    const rect = this.container.getBoundingClientRect();
    this.pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    this.pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

    this.raycaster.setFromCamera(this.pointer, this.camera);
    const intersects = this.raycaster.intersectObjects(this.splineHelperObjects, false);

    if (intersects.length > 0) {
      const object = intersects[0].object;
      if (object !== this.transformControl.object) {
        this.transformControl.attach(object);
      }
    }
  }

  addSplineObject(position , index) {
    // const material = new THREE.MeshBasicMaterial({
    //   color: Math.random() * 0xffffff
    // });
    // 3. 创建精灵对象
    const object = new THREE.Sprite(this.pointGeometry);
    object.center.set(0.5, 0.15);
    object.scale.set(3, 6, 3);
    object.resetIndex = index;

    if (position) {
      object.position.copy(position);
    } else {
      object.position.x = Math.random() * 30;
      object.position.y = Math.random() * 0;
      object.position.z = Math.random() * 30;
    }

    object.castShadow = true;
    object.receiveShadow = true;
    this.scene.add(object);
    this.splineHelperObjects.push(object);
    this.positions.push(object.position);
    return object;
  }

  addPoint(position) {
    const point = this.addSplineObject(position);
    this.updateSplineOutline();
    this.render();
    console.log(point);

    this.transformControl.attach(point);
    return point;
  }

  removePoint() {
    if (this.splineHelperObjects.length <= 4) return;

    const point = this.splineHelperObjects.pop();
    this.positions.pop();

    if (this.transformControl.object === point) {
      this.transformControl.detach();
    }
    this.scene.remove(point);

    this.updateSplineOutline();
    this.render();
  }

  updateSplineOutline() {
    for (const k in this.splines) {
      const spline = this.splines[k];
      const position = spline.mesh.geometry.attributes.position;

      for (let i = 0; i < this.ARC_SEGMENTS; i++) {
        const t = i / (this.ARC_SEGMENTS - 1);
        spline.getPoint(t, this.point);
        position.setXYZ(i, this.point.x, this.point.y, this.point.z);
      }
      position.needsUpdate = true;
    }
  }

  render() {
    if (this.splines.uniform) {
      this.splines.uniform.mesh.visible = this.params.uniform;
      this.splines.centripetal.mesh.visible = this.params.centripetal;
      this.splines.chordal.mesh.visible = this.params.chordal;
    }
  }

  dispose(all) {
    // 移除事件监听
    this.container.removeEventListener('pointerdown', this.onPointerDown);
    this.container.removeEventListener('pointerup', this.onPointerUp);
    this.container.removeEventListener('pointermove', this.onPointerMove);

    // 移除场景中的对象

    Object.values(this.splines).forEach(spline => this.scene.remove(spline.mesh));
    this.scene.remove(this.transformControl.getHelper());
    this.scene.remove(this.transformControl);

    // 清理引用
    this.splines = {};
    this.positions = [];

    if(all){
      this.splineHelperObjects.forEach((obj,index) => {
        this.scene.remove(obj);
      })
      this.splineHelperObjects = [];
    }
  }

  removeSpline(idIndex) {
    
    this.splineHelperObjects.forEach((obj,index) => {
      if(idIndex == obj.resetIndex){
        this.scene.remove(obj);
        this.splineHelperObjects.splice(index,1);
      }
    });
  }
}